home *** CD-ROM | disk | FTP | other *** search
/ Clickx 96 / Clickx 96.iso / software / tools / tool / xbmc-10.1.exe / addons / script.module.pil / lib / PIL / JpegImagePlugin.py < prev    next >
Encoding:
Python Source  |  2009-05-22  |  16.0 KB  |  493 lines

  1. #
  2. # The Python Imaging Library.
  3. # $Id$
  4. #
  5. # JPEG (JFIF) file handling
  6. #
  7. # See "Digital Compression and Coding of Continous-Tone Still Images,
  8. # Part 1, Requirements and Guidelines" (CCITT T.81 / ISO 10918-1)
  9. #
  10. # History:
  11. # 1995-09-09 fl   Created
  12. # 1995-09-13 fl   Added full parser
  13. # 1996-03-25 fl   Added hack to use the IJG command line utilities
  14. # 1996-05-05 fl   Workaround Photoshop 2.5 CMYK polarity bug
  15. # 1996-05-28 fl   Added draft support, JFIF version (0.1)
  16. # 1996-12-30 fl   Added encoder options, added progression property (0.2)
  17. # 1997-08-27 fl   Save mode 1 images as BW (0.3)
  18. # 1998-07-12 fl   Added YCbCr to draft and save methods (0.4)
  19. # 1998-10-19 fl   Don't hang on files using 16-bit DQT's (0.4.1)
  20. # 2001-04-16 fl   Extract DPI settings from JFIF files (0.4.2)
  21. # 2002-07-01 fl   Skip pad bytes before markers; identify Exif files (0.4.3)
  22. # 2003-04-25 fl   Added experimental EXIF decoder (0.5)
  23. # 2003-06-06 fl   Added experimental EXIF GPSinfo decoder
  24. # 2003-09-13 fl   Extract COM markers
  25. # 2009-09-06 fl   Added icc_profile support (from Florian Hoech)
  26. # 2009-03-06 fl   Changed CMYK handling; always use Adobe polarity (0.6)
  27. # 2009-03-08 fl   Added subsampling support (from Justin Huff).
  28. #
  29. # Copyright (c) 1997-2003 by Secret Labs AB.
  30. # Copyright (c) 1995-1996 by Fredrik Lundh.
  31. #
  32. # See the README file for information on usage and redistribution.
  33. #
  34.  
  35. __version__ = "0.6"
  36.  
  37. import array, struct
  38. import string
  39. import Image, ImageFile
  40.  
  41. def i16(c,o=0):
  42.     return ord(c[o+1]) + (ord(c[o])<<8)
  43.  
  44. def i32(c,o=0):
  45.     return ord(c[o+3]) + (ord(c[o+2])<<8) + (ord(c[o+1])<<16) + (ord(c[o])<<24)
  46.  
  47. #
  48. # Parser
  49.  
  50. def Skip(self, marker):
  51.     n = i16(self.fp.read(2))-2
  52.     ImageFile._safe_read(self.fp, n)
  53.  
  54. def APP(self, marker):
  55.     #
  56.     # Application marker.  Store these in the APP dictionary.
  57.     # Also look for well-known application markers.
  58.  
  59.     n = i16(self.fp.read(2))-2
  60.     s = ImageFile._safe_read(self.fp, n)
  61.  
  62.     app = "APP%d" % (marker&15)
  63.  
  64.     self.app[app] = s # compatibility
  65.     self.applist.append((app, s))
  66.  
  67.     if marker == 0xFFE0 and s[:4] == "JFIF":
  68.         # extract JFIF information
  69.         self.info["jfif"] = version = i16(s, 5) # version
  70.         self.info["jfif_version"] = divmod(version, 256)
  71.         # extract JFIF properties
  72.         try:
  73.             jfif_unit = ord(s[7])
  74.             jfif_density = i16(s, 8), i16(s, 10)
  75.         except:
  76.             pass
  77.         else:
  78.             if jfif_unit == 1:
  79.                 self.info["dpi"] = jfif_density
  80.             self.info["jfif_unit"] = jfif_unit
  81.             self.info["jfif_density"] = jfif_density
  82.     elif marker == 0xFFE1 and s[:5] == "Exif\0":
  83.         # extract Exif information (incomplete)
  84.         self.info["exif"] = s # FIXME: value will change
  85.     elif marker == 0xFFE2 and s[:5] == "FPXR\0":
  86.         # extract FlashPix information (incomplete)
  87.         self.info["flashpix"] = s # FIXME: value will change
  88.     elif marker == 0xFFE2 and s[:12] == "ICC_PROFILE\0":
  89.         # Since an ICC profile can be larger than the maximum size of
  90.         # a JPEG marker (64K), we need provisions to split it into
  91.         # multiple markers. The format defined by the ICC specifies
  92.         # one or more APP2 markers containing the following data:
  93.         #   Identifying string      ASCII "ICC_PROFILE\0"  (12 bytes)
  94.         #   Marker sequence number  1, 2, etc (1 byte)
  95.         #   Number of markers       Total of APP2's used (1 byte)
  96.         #   Profile data            (remainder of APP2 data)
  97.         # Decoders should use the marker sequence numbers to
  98.         # reassemble the profile, rather than assuming that the APP2
  99.         # markers appear in the correct sequence.
  100.         self.icclist.append(s)
  101.     elif marker == 0xFFEE and s[:5] == "Adobe":
  102.         self.info["adobe"] = i16(s, 5)
  103.         # extract Adobe custom properties
  104.         try:
  105.             adobe_transform = ord(s[1])
  106.         except:
  107.             pass
  108.         else:
  109.             self.info["adobe_transform"] = adobe_transform
  110.  
  111. def COM(self, marker):
  112.     #
  113.     # Comment marker.  Store these in the APP dictionary.
  114.  
  115.     n = i16(self.fp.read(2))-2
  116.     s = ImageFile._safe_read(self.fp, n)
  117.  
  118.     self.app["COM"] = s # compatibility
  119.     self.applist.append(("COM", s))
  120.  
  121. def SOF(self, marker):
  122.     #
  123.     # Start of frame marker.  Defines the size and mode of the
  124.     # image.  JPEG is colour blind, so we use some simple
  125.     # heuristics to map the number of layers to an appropriate
  126.     # mode.  Note that this could be made a bit brighter, by
  127.     # looking for JFIF and Adobe APP markers.
  128.  
  129.     n = i16(self.fp.read(2))-2
  130.     s = ImageFile._safe_read(self.fp, n)
  131.     self.size = i16(s[3:]), i16(s[1:])
  132.  
  133.     self.bits = ord(s[0])
  134.     if self.bits != 8:
  135.         raise SyntaxError("cannot handle %d-bit layers" % self.bits)
  136.  
  137.     self.layers = ord(s[5])
  138.     if self.layers == 1:
  139.         self.mode = "L"
  140.     elif self.layers == 3:
  141.         self.mode = "RGB"
  142.     elif self.layers == 4:
  143.         self.mode = "CMYK"
  144.     else:
  145.         raise SyntaxError("cannot handle %d-layer images" % self.layers)
  146.  
  147.     if marker in [0xFFC2, 0xFFC6, 0xFFCA, 0xFFCE]:
  148.         self.info["progressive"] = self.info["progression"] = 1
  149.  
  150.     if self.icclist:
  151.         # fixup icc profile
  152.         self.icclist.sort() # sort by sequence number
  153.         if ord(self.icclist[0][13]) == len(self.icclist):
  154.             profile = []
  155.             for p in self.icclist:
  156.                 profile.append(p[14:])
  157.             icc_profile = string.join(profile, "")
  158.         else:
  159.             icc_profile = None # wrong number of fragments
  160.         self.info["icc_profile"] = icc_profile
  161.         self.icclist = None
  162.  
  163.     for i in range(6, len(s), 3):
  164.         t = s[i:i+3]
  165.         # 4-tuples: id, vsamp, hsamp, qtable
  166.         self.layer.append((t[0], ord(t[1])/16, ord(t[1])&15, ord(t[2])))
  167.  
  168. def DQT(self, marker):
  169.     #
  170.     # Define quantization table.  Support baseline 8-bit tables
  171.     # only.  Note that there might be more than one table in
  172.     # each marker.
  173.  
  174.     # FIXME: The quantization tables can be used to estimate the
  175.     # compression quality.
  176.  
  177.     n = i16(self.fp.read(2))-2
  178.     s = ImageFile._safe_read(self.fp, n)
  179.     while len(s):
  180.         if len(s) < 65:
  181.             raise SyntaxError("bad quantization table marker")
  182.         v = ord(s[0])
  183.         if v/16 == 0:
  184.             self.quantization[v&15] = array.array("b", s[1:65])
  185.             s = s[65:]
  186.         else:
  187.             return # FIXME: add code to read 16-bit tables!
  188.             # raise SyntaxError, "bad quantization table element size"
  189.  
  190.  
  191. #
  192. # JPEG marker table
  193.  
  194. MARKER = {
  195.     0xFFC0: ("SOF0", "Baseline DCT", SOF),
  196.     0xFFC1: ("SOF1", "Extended Sequential DCT", SOF),
  197.     0xFFC2: ("SOF2", "Progressive DCT", SOF),
  198.     0xFFC3: ("SOF3", "Spatial lossless", SOF),
  199.     0xFFC4: ("DHT", "Define Huffman table", Skip),
  200.     0xFFC5: ("SOF5", "Differential sequential DCT", SOF),
  201.     0xFFC6: ("SOF6", "Differential progressive DCT", SOF),
  202.     0xFFC7: ("SOF7", "Differential spatial", SOF),
  203.     0xFFC8: ("JPG", "Extension", None),
  204.     0xFFC9: ("SOF9", "Extended sequential DCT (AC)", SOF),
  205.     0xFFCA: ("SOF10", "Progressive DCT (AC)", SOF),
  206.     0xFFCB: ("SOF11", "Spatial lossless DCT (AC)", SOF),
  207.     0xFFCC: ("DAC", "Define arithmetic coding conditioning", Skip),
  208.     0xFFCD: ("SOF13", "Differential sequential DCT (AC)", SOF),
  209.     0xFFCE: ("SOF14", "Differential progressive DCT (AC)", SOF),
  210.     0xFFCF: ("SOF15", "Differential spatial (AC)", SOF),
  211.     0xFFD0: ("RST0", "Restart 0", None),
  212.     0xFFD1: ("RST1", "Restart 1", None),
  213.     0xFFD2: ("RST2", "Restart 2", None),
  214.     0xFFD3: ("RST3", "Restart 3", None),
  215.     0xFFD4: ("RST4", "Restart 4", None),
  216.     0xFFD5: ("RST5", "Restart 5", None),
  217.     0xFFD6: ("RST6", "Restart 6", None),
  218.     0xFFD7: ("RST7", "Restart 7", None),
  219.     0xFFD8: ("SOI", "Start of image", None),
  220.     0xFFD9: ("EOI", "End of image", None),
  221.     0xFFDA: ("SOS", "Start of scan", Skip),
  222.     0xFFDB: ("DQT", "Define quantization table", DQT),
  223.     0xFFDC: ("DNL", "Define number of lines", Skip),
  224.     0xFFDD: ("DRI", "Define restart interval", Skip),
  225.     0xFFDE: ("DHP", "Define hierarchical progression", SOF),
  226.     0xFFDF: ("EXP", "Expand reference component", Skip),
  227.     0xFFE0: ("APP0", "Application segment 0", APP),
  228.     0xFFE1: ("APP1", "Application segment 1", APP),
  229.     0xFFE2: ("APP2", "Application segment 2", APP),
  230.     0xFFE3: ("APP3", "Application segment 3", APP),
  231.     0xFFE4: ("APP4", "Application segment 4", APP),
  232.     0xFFE5: ("APP5", "Application segment 5", APP),
  233.     0xFFE6: ("APP6", "Application segment 6", APP),
  234.     0xFFE7: ("APP7", "Application segment 7", APP),
  235.     0xFFE8: ("APP8", "Application segment 8", APP),
  236.     0xFFE9: ("APP9", "Application segment 9", APP),
  237.     0xFFEA: ("APP10", "Application segment 10", APP),
  238.     0xFFEB: ("APP11", "Application segment 11", APP),
  239.     0xFFEC: ("APP12", "Application segment 12", APP),
  240.     0xFFED: ("APP13", "Application segment 13", APP),
  241.     0xFFEE: ("APP14", "Application segment 14", APP),
  242.     0xFFEF: ("APP15", "Application segment 15", APP),
  243.     0xFFF0: ("JPG0", "Extension 0", None),
  244.     0xFFF1: ("JPG1", "Extension 1", None),
  245.     0xFFF2: ("JPG2", "Extension 2", None),
  246.     0xFFF3: ("JPG3", "Extension 3", None),
  247.     0xFFF4: ("JPG4", "Extension 4", None),
  248.     0xFFF5: ("JPG5", "Extension 5", None),
  249.     0xFFF6: ("JPG6", "Extension 6", None),
  250.     0xFFF7: ("JPG7", "Extension 7", None),
  251.     0xFFF8: ("JPG8", "Extension 8", None),
  252.     0xFFF9: ("JPG9", "Extension 9", None),
  253.     0xFFFA: ("JPG10", "Extension 10", None),
  254.     0xFFFB: ("JPG11", "Extension 11", None),
  255.     0xFFFC: ("JPG12", "Extension 12", None),
  256.     0xFFFD: ("JPG13", "Extension 13", None),
  257.     0xFFFE: ("COM", "Comment", COM)
  258. }
  259.  
  260.  
  261. def _accept(prefix):
  262.     return prefix[0] == "\377"
  263.  
  264. ##
  265. # Image plugin for JPEG and JFIF images.
  266.  
  267. class JpegImageFile(ImageFile.ImageFile):
  268.  
  269.     format = "JPEG"
  270.     format_description = "JPEG (ISO 10918)"
  271.  
  272.     def _open(self):
  273.  
  274.         s = self.fp.read(1)
  275.  
  276.         if ord(s[0]) != 255:
  277.             raise SyntaxError("not a JPEG file")
  278.  
  279.         # Create attributes
  280.         self.bits = self.layers = 0
  281.  
  282.         # JPEG specifics (internal)
  283.         self.layer = []
  284.         self.huffman_dc = {}
  285.         self.huffman_ac = {}
  286.         self.quantization = {}
  287.         self.app = {} # compatibility
  288.         self.applist = []
  289.         self.icclist = []
  290.  
  291.         while 1:
  292.  
  293.             s = s + self.fp.read(1)
  294.  
  295.             i = i16(s)
  296.  
  297.             if MARKER.has_key(i):
  298.                 name, description, handler = MARKER[i]
  299.                 # print hex(i), name, description
  300.                 if handler is not None:
  301.                     handler(self, i)
  302.                 if i == 0xFFDA: # start of scan
  303.                     rawmode = self.mode
  304.                     if self.mode == "CMYK":
  305.                         rawmode = "CMYK;I" # assume adobe conventions
  306.                     self.tile = [("jpeg", (0,0) + self.size, 0, (rawmode, ""))]
  307.                     # self.__offset = self.fp.tell()
  308.                     break
  309.                 s = self.fp.read(1)
  310.             elif i == 0 or i == 65535:
  311.                 # padded marker or junk; move on
  312.                 s = "\xff"
  313.             else:
  314.                 raise SyntaxError("no marker found")
  315.  
  316.     def draft(self, mode, size):
  317.  
  318.         if len(self.tile) != 1:
  319.             return
  320.  
  321.         d, e, o, a = self.tile[0]
  322.         scale = 0
  323.  
  324.         if a[0] == "RGB" and mode in ["L", "YCbCr"]:
  325.             self.mode = mode
  326.             a = mode, ""
  327.  
  328.         if size:
  329.             scale = max(self.size[0] / size[0], self.size[1] / size[1])
  330.             for s in [8, 4, 2, 1]:
  331.                 if scale >= s:
  332.                     break
  333.             e = e[0], e[1], (e[2]-e[0]+s-1)/s+e[0], (e[3]-e[1]+s-1)/s+e[1]
  334.             self.size = ((self.size[0]+s-1)/s, (self.size[1]+s-1)/s)
  335.             scale = s
  336.  
  337.         self.tile = [(d, e, o, a)]
  338.         self.decoderconfig = (scale, 1)
  339.  
  340.         return self
  341.  
  342.     def load_djpeg(self):
  343.  
  344.         # ALTERNATIVE: handle JPEGs via the IJG command line utilities
  345.  
  346.         import tempfile, os
  347.         file = tempfile.mktemp()
  348.         os.system("djpeg %s >%s" % (self.filename, file))
  349.  
  350.         try:
  351.             self.im = Image.core.open_ppm(file)
  352.         finally:
  353.             try: os.unlink(file)
  354.             except: pass
  355.  
  356.         self.mode = self.im.mode
  357.         self.size = self.im.size
  358.  
  359.         self.tile = []
  360.  
  361.     def _getexif(self):
  362.         # Extract EXIF information.  This method is highly experimental,
  363.         # and is likely to be replaced with something better in a future
  364.         # version.
  365.         import TiffImagePlugin, StringIO
  366.         def fixup(value):
  367.             if len(value) == 1:
  368.                 return value[0]
  369.             return value
  370.         # The EXIF record consists of a TIFF file embedded in a JPEG
  371.         # application marker (!).
  372.         try:
  373.             data = self.info["exif"]
  374.         except KeyError:
  375.             return None
  376.         file = StringIO.StringIO(data[6:])
  377.         head = file.read(8)
  378.         exif = {}
  379.         # process dictionary
  380.         info = TiffImagePlugin.ImageFileDirectory(head)
  381.         info.load(file)
  382.         for key, value in info.items():
  383.             exif[key] = fixup(value)
  384.         # get exif extension
  385.         try:
  386.             file.seek(exif[0x8769])
  387.         except KeyError:
  388.             pass
  389.         else:
  390.             info = TiffImagePlugin.ImageFileDirectory(head)
  391.             info.load(file)
  392.             for key, value in info.items():
  393.                 exif[key] = fixup(value)
  394.         # get gpsinfo extension
  395.         try:
  396.             file.seek(exif[0x8825])
  397.         except KeyError:
  398.             pass
  399.         else:
  400.             info = TiffImagePlugin.ImageFileDirectory(head)
  401.             info.load(file)
  402.             exif[0x8825] = gps = {}
  403.             for key, value in info.items():
  404.                 gps[key] = fixup(value)
  405.         return exif
  406.  
  407. # --------------------------------------------------------------------
  408. # stuff to save JPEG files
  409.  
  410. RAWMODE = {
  411.     "1": "L",
  412.     "L": "L",
  413.     "RGB": "RGB",
  414.     "RGBA": "RGB",
  415.     "RGBX": "RGB",
  416.     "CMYK": "CMYK;I", # assume adobe conventions
  417.     "YCbCr": "YCbCr",
  418. }
  419.  
  420. def _save(im, fp, filename):
  421.  
  422.     try:
  423.         rawmode = RAWMODE[im.mode]
  424.     except KeyError:
  425.         raise IOError("cannot write mode %s as JPEG" % im.mode)
  426.  
  427.     info = im.encoderinfo
  428.  
  429.     dpi = info.get("dpi", (0, 0))
  430.  
  431.     subsampling = info.get("subsampling", -1)
  432.     if subsampling == "4:4:4":
  433.         subsampling = 0
  434.     elif subsampling == "4:2:2":
  435.         subsampling = 1
  436.     elif subsampling == "4:1:1":
  437.         subsampling = 2
  438.  
  439.     extra = ""
  440.  
  441.     icc_profile = info.get("icc_profile")
  442.     if icc_profile:
  443.         ICC_OVERHEAD_LEN = 14
  444.         MAX_BYTES_IN_MARKER = 65533
  445.         MAX_DATA_BYTES_IN_MARKER = MAX_BYTES_IN_MARKER - ICC_OVERHEAD_LEN
  446.         markers = []
  447.         while icc_profile:
  448.             markers.append(icc_profile[:MAX_DATA_BYTES_IN_MARKER])
  449.             icc_profile = icc_profile[MAX_DATA_BYTES_IN_MARKER:]
  450.         i = 1
  451.         for marker in markers:
  452.             size = struct.pack(">H", 2 + ICC_OVERHEAD_LEN + len(marker))
  453.             extra = extra + ("\xFF\xE2" + size + "ICC_PROFILE\0" + chr(i) + chr(len(markers)) + marker)
  454.             i = i + 1
  455.  
  456.     # get keyword arguments
  457.     im.encoderconfig = (
  458.         info.get("quality", 0),
  459.         # "progressive" is the official name, but older documentation
  460.         # says "progression"
  461.         # FIXME: issue a warning if the wrong form is used (post-1.1.7)
  462.         info.has_key("progressive") or info.has_key("progression"),
  463.         info.get("smooth", 0),
  464.         info.has_key("optimize"),
  465.         info.get("streamtype", 0),
  466.         dpi[0], dpi[1],
  467.         subsampling,
  468.         extra,
  469.         )
  470.  
  471.     ImageFile._save(im, fp, [("jpeg", (0,0)+im.size, 0, rawmode)])
  472.  
  473. def _save_cjpeg(im, fp, filename):
  474.     # ALTERNATIVE: handle JPEGs via the IJG command line utilities.
  475.     import os
  476.     file = im._dump()
  477.     os.system("cjpeg %s >%s" % (file, filename))
  478.     try: os.unlink(file)
  479.     except: pass
  480.  
  481. # -------------------------------------------------------------------q-
  482. # Registry stuff
  483.  
  484. Image.register_open("JPEG", JpegImageFile, _accept)
  485. Image.register_save("JPEG", _save)
  486.  
  487. Image.register_extension("JPEG", ".jfif")
  488. Image.register_extension("JPEG", ".jpe")
  489. Image.register_extension("JPEG", ".jpg")
  490. Image.register_extension("JPEG", ".jpeg")
  491.  
  492. Image.register_mime("JPEG", "image/jpeg")
  493.